# -*- encoding:utf-8 -*-
import zhcxgdDev
from functools import wraps


def print_results(f):
    @wraps(f)
    def wrapper(*args, **kwds):
        res = f(*args, **kwds)
        if isinstance(res,int):
            if res == 0:
                print("运行 "+f.__name__+" 失败")
            elif res == -1:
                print("USB-CAN设备不存在或USB掉线")
        return res
    return wrapper

class Remote(object):
    def __init__(self,ID,RemoteFlag,ExternFlag):
        self.ID = ID
        if isinstance(RemoteFlag,bool):
            self.RemoteFlag = RemoteFlag
        elif isinstance(RemoteFlag,int):
            self.RemoteFlag = False if RemoteFlag == 0 else True
        else:
            raise TypeError("RemoteFlag type error")
        if isinstance(ExternFlag,bool):
            self.ExternFlag = ExternFlag
        elif isinstance(ExternFlag,int):
            self.ExternFlag = False if ExternFlag == 0 else True
        else:
            raise TypeError("ExternFlag type error")

class zhcxgd_can(object):
    BAUDRATE_10K   = (0x31,0x1C)
    BAUDRATE_20K   = (0x18,0x1C)
    BAUDRATE_40K   = (0x87,0xFF)
    BAUDRATE_50K   = (0x09,0x1C)
    BAUDRATE_80K   = (0x83,0xFF)
    BAUDRATE_100K  = (0x04,0x1C)
    BAUDRATE_125K  = (0x03,0x1C)
    BAUDRATE_200K  = (0x81,0xFA)
    BAUDRATE_250K  = (0x01,0x1C)
    BAUDRATE_400K  = (0x80,0xFA)
    BAUDRATE_500K  = (0x00,0x1C)
    BAUDRATE_666K  = (0x80,0xB6)
    BAUDRATE_800K  = (0x00,0x16)
    BAUDRATE_1000K = (0x00,0x14)
    BAUDRATE_33K33 = (0x09,0x6F)
    BAUDRATE_66K66 = (0x04,0x6F)
    BAUDRATE_83K33 = (0x03,0x6F)
    
    FILTER_ALL      = 0
    FILTER_STANDARD = 2
    FILTER_EXTEND   = 3
    
    NORMAL_MODE     = 0
    SILENT_MODE     = 1
    LOOP_BACK_MODE  = 2
    
    CHANNEL1 = 0
    CHANNEL2 = 1
    RecDataTypeTupe = 0
    RecDataTypeDict = 1
    
    def __init__(self):
        self.nDeviceType = 4;
        self.nDeviceInd = 0;
        
    def open(self,DeviceType=4,DeviceInd=0):
        """DeviceType: USBCAN-2A,USBCAN-2C,CANalyst-II 都是4
        DeviceInd:第一个插入的设备是0，第二个插入的设备是1，以此类推
        """
        self.nDeviceInd = DeviceInd
        self.nDeviceType = DeviceType
        if zhcxgdDev.OpenDevice(DeviceType,DeviceInd) != 1:
            raise Exception("open Device Error")
            
    @print_results
    def close(self):
        res = zhcxgdDev.ClsoeDevice(self.nDeviceType,self.nDeviceInd);
        
    @print_results
    def InitCAN(self,CANInd=0,AccCode=0x80000000,AccMask=0xFFFFFFFF,Filter=FILTER_ALL,
        BaudRate=BAUDRATE_250K,mode=NORMAL_MODE):
        """CANInd:通道号
        AccCode，AccMask左对齐
        """
        zhcxgdDev.InitCAN(self.nDeviceType,self.nDeviceInd,CANInd,
            AccCode,AccMask,Filter,BaudRate[0],BaudRate[1],mode)
        return zhcxgd_can_channel(self.nDeviceType,self.nDeviceInd,CANInd)
        
    @print_results
    def ReadBoardInfo(self):
        res,vbi = zhcxgdDev.ReadBoardInfo(self.nDeviceType,self.nDeviceInd)
        if res == 1:
            print("hw Version:{}".format(vbi["hw_Version"]))
            print("fw Version:{}".format(vbi["fw_Version"]))
            print("irq Num:{}".format(vbi["irq_Num"]))
            print("can Num:{}".format(vbi["can_Num"]))
            print("Serial Num:{}".format(vbi["str_Serial_Num"]))
            print("hw Type:{}".format(vbi["str_hw_Type"]))
        return res;

    @print_results
    def ClearBuffer(self,CANInd):
        return zhcxgdDev.ClearBuffer(self.nDeviceType,self.nDeviceInd,CANInd)

    @print_results
    def GetReceiveNum(self,CANInd):
        return zhcxgdDev.GetReceiveNum(self.nDeviceType,self.nDeviceInd,CANInd)
        
    @print_results
    def StartCAN(self,CANInd):
        return zhcxgdDev.StartCAN(self.nDeviceType,self.nDeviceInd,CANInd)
        
    @print_results
    def ResetCAN(self,CANInd):
        return zhcxgdDev.ResetCAN(self.nDeviceType,self.nDeviceInd,CANInd)
        
    def Transmit(self,CANInd,pyvco_lsit):
        """ pyvco_lsit :
        [
            ID,#帧ID
            RemoteFlag,#是否是远程帧。=0时为为数据帧，=1时为远程帧（数据段空）
            ExternFlag,#是否是扩展帧。=0时为标准帧（11位ID），=1时为扩展帧（29位ID）。
            Data#CAN帧的数据,最大是8个字节
        ]
        """
        sen_len = zhcxgdDev.Transmit(self.nDeviceType,self.nDeviceInd,CANInd,pyvco_lsit)
        if sen_len < 0:
            raise Exception("USB-CAN设备不存在或USB掉线")
        return sen_len
        
    @print_results
    def Receive(self,CANInd,RecDataType=RecDataTypeTupe,Length=2500):
        return zhcxgdDev.Receive(self.nDeviceType,self.nDeviceInd,CANInd,Length,RecDataType)
        
    @print_results
    def UsbDeviceReset(self,DeviceType=None,DeviceInd=None):
        if DeviceType is None or DeviceInd is None:
            DeviceType = self.nDeviceType
            DeviceInd  = self.nDeviceInd
        return zhcxgdDev.UsbDeviceReset(DeviceType,DeviceInd)
        
    def FindUsbDevice(self):
        return zhcxgdDev.FindUsbDevice()
        
class zhcxgd_can_channel(zhcxgd_can):
    def __init__(self,DeviceType,DeviceInd,CANInd):
        self.nDeviceType = DeviceType
        self.nDeviceInd = DeviceInd
        self.nCANInd = CANInd
        self.remote = None
        self.printHead = True
        
    def ClearBuffer(self):
        return super().ClearBuffer(self.nCANInd)
        
    def GetReceiveNum(self):
        return super().GetReceiveNum(self.nCANInd)
        
    def StartCAN(self):
        return super().StartCAN(self.nCANInd)
        
    def ResetCAN(self):
        return super().ResetCAN(self.nCANInd)
        
    def Transmit(self,*sdtat):
        if len(sdtat) == 1:
            if isinstance(sdtat[0],bytes):
                pyvco_lsit = self.remote;
                pyvco_lsit[3] = sdtat[0]
            else:
                pyvco_lsit = sdtat[0]
        elif len(sdtat) == 2:
            if isinstance(sdtat[0],int) and isinstance(sdtat[1],bytes):
                pyvco_lsit = self.remote;
                pyvco_lsit[0] = sdtat[0]
                pyvco_lsit[3] = sdtat[1]
        #print(pyvco_lsit)
        return super().Transmit(self.nCANInd,pyvco_lsit)
        
    def setRemote(self,remote):
        """
            ID,#帧ID
            RemoteFlag,#是否是远程帧。=0时为为数据帧，=1时为远程帧（数据段空）
            ExternFlag,#是否是扩展帧。=0时为标准帧（11位ID），=1时为扩展帧（29位ID）。
        """
        self.remote = [remote.ID,remote.RemoteFlag,remote.ExternFlag,b'']
        
    def Receive(self,RecDataType=zhcxgd_can.RecDataTypeTupe,Length=2500):
        return super().Receive(self.nCANInd,RecDataType,Length)
        
    def print_recive(self):
        rec = self.Receive()
        if self.printHead:
            print("{},{: ^8},{},{},{},{}".format("时间标识","ID","帧类型","帧格式","长度","数据"))
            self.printHead = False
        for dt in rec:
            frm_type = "数据帧" if dt[3] == 0 else "远程帧"
            frm_fmt  = "标准帧" if dt[4] == 0 else "扩展帧"
            rec_data = " ".join(map(lambda x:"{:X}".format(x),dt[6]))
            print("{:08X},{:08X},{},{},{: 4d},{}".format(dt[1],dt[0],frm_type,frm_fmt,dt[5],rec_data ))
            
            